package com.dzl.admin;

import com.alibaba.fastjson.JSONObject;
import com.dzl.base.controller.BaseController;
import com.dzl.base.pojo.BaseData;
import com.dzl.base.service.BaseDataService;
import com.dzl.config.ApplicationConfiguration;
import com.dzl.constant.CommonConstants;
import com.dzl.util.EmptyUtils;
import com.dzl.util.HttpUtil;
import com.dzl.util.JsonResult;
import com.dzl.util.RedisUtil;
import com.dzl.util.wx.third.ComponentConfig;
import com.dzl.util.wx.third.WebChatCatchUtil;
import com.dzl.util.wx.third.WeixinImSetting;
import com.dzl.util.wx.third.WxThirdUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.open.api.WxOpenConfigStorage;
import me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage;
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 全量发布小程序控制类
 * @author liuguanjun
 * @date 2022-01-10 15:08:01
 * @return
 **/
@Slf4j
@RestController
@RequestMapping("/fullReleaseApplet")
public class FullReleaseAppletController extends BaseController{



	@Autowired
	private BaseDataService baseDataService;

	/**
	 * 授权事件接收URL
	 * 用于接收取消授权通知、授权成功通知、授权更新通知，也用于接收验证票据
	 * @paramtimestamp 事件戳
	 * @paramnonce 随机数
	 * @paramencType 加密类型，为 aes
	 * @parammsgSignature 消息体签名
	 * @parampostData 密文，对应POST请求的数据
	 */
	@PostMapping("/receive")
	public String receiveWxEvent(@RequestParam("timestamp") String timestamp,
								 @RequestParam("nonce") String nonce,
								 @RequestParam(name = "encrypt_type", required = false) String encType,
								 @RequestParam(name = "msg_signature", required = false) String msgSignature,
								 @RequestBody(required = false) String postData) {
		log.info("=========================开始-接收微信服务器的授权事件接收URL=========================");
		log.info("=========================授权事件接收URL接收微信请求：【encType=[{}], 消息体签名msgSignature=[{}], 时间戳timestamp=[{}], 随机数nonce=[{}], postData=[\n{}\n]】", encType, msgSignature, timestamp, nonce, postData);
		try {
			//解密消息
			WxOpenConfigStorage wxOpenConfigStorage = new WxOpenInMemoryConfigStorage();
			wxOpenConfigStorage.setComponentAppId(ComponentConfig.sComponentAppId);
			wxOpenConfigStorage.setComponentAesKey(ComponentConfig.sEncodingAESKey);
			wxOpenConfigStorage.setComponentToken(ComponentConfig.sToken);
			wxOpenConfigStorage.setComponentAppSecret(ComponentConfig.sComponentAppSecret);
			WxOpenXmlMessage result = WxOpenXmlMessage.fromEncryptedXml(postData, wxOpenConfigStorage, timestamp, nonce, msgSignature);
			log.info("====================receive result:"+result.toString());
			String infoType = result.getInfoType();
			//infoType:验证票据、新增授权、更新授权、取消授权，这里可以根据不同类型做业务逻辑处理
			log.info("====================receive InfoType:"+infoType);
			switch (infoType){
				case "component_verify_ticket":   //接收票据 【component_verify_ticket】
					String ComponentVerifyTicket = result.getComponentVerifyTicket();
					WebChatCatchUtil.setWeixinOpenComponentVerifyTicket(ComponentVerifyTicket,60 * 60 * 12);   //将票据值写入Redis缓存中 缓存12小时
					log.info("====================COMPONENT_VERIFY_TICKET:"+ComponentVerifyTicket);
					BaseData baseData = baseDataService.findByCode("componentVerifyTicket");
					// 存数据库
					if(EmptyUtils.isNotEmpty(baseData)){
						baseData.setValue(ComponentVerifyTicket);
						baseData.setUpdateTime(new Date());
						baseDataService.updateByPrimaryKeySelective(baseData);
					}else{
						baseData = new BaseData();
						baseData.setCode("componentVerifyTicket");
						baseData.setName("第三方平台授权事件接收URL接收票据参数");
						baseData.setStatus(CommonConstants.YES);
						baseData.setCreateTime(new Date());
						baseData.setValue(ComponentVerifyTicket);
						baseData.setUpdateTime(new Date());
						baseDataService.insertSelective(baseData);
					}
					break;
				case "authorized": //授权成功
					//this.disposeAuthResult(result);
					wechatPlatformAauthcode(result.getAuthorizationCode());
					log.info("====================authorized");
					break;
				case "unauthorized"://用户取消授权
					//todo 取消授权
					String authorizerAppId = result.getAuthorizerAppid();
					//customerMpDao.updateAuthorizationFlag(authorizerAppId);
					this.disposeAuthResult(result);
					log.info("====================unauthorized");
					break;
				case "updateauthorized"://授权变更
					this.disposeAuthResult(result);
					log.info("====================updateauthorized");
					break;
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("=========================解析微信服务器的授权事件信息异常，【{}】",e.getMessage());
			return "fail";
		}
		log.info("=========================结束-接收微信服务器的授权事件接收URL=========================");
		return "success";
	}

	/**
	 * 消息与事件接收URL
	 * 该 URL 用于接收已授权公众号的消息和事件，消息内容、消息格式、签名方式、加密方式与普通公众号接收的一致，
	 * 唯一区别在于签名 token 和加密 symmetric_key 使用的是服务方申请时所填写的信息。由于消息具体内容不会变更，
	 * 故根据消息内容里的 ToUserName，服务方是可以区分出具体消息所属的公众号
	 * @param postData 密文，对应POST请求的数据
	 * @param appId 必须提供如下形式的 url：www.abc.com/aaa/$APPID$/bbb/cgi，其中$APPID$在实际推送时会替换成所属的已授权公众号/小程序接的 appid
	 * @param signature
	 * @param timestamp 事件戳
	 * @param nonce 随机数
	 * @param openid
	 * @param encType 加密类型，为 aes
	 * @param msgSignature 消息体签名
	 * @return
	 */
	@PostMapping("/{appId}/callback")
	public Object callback(@RequestBody(required = false) String postData,
						   @PathVariable("appId") String appId,
						   @RequestParam("signature") String signature,
						   @RequestParam("timestamp") String timestamp,
						   @RequestParam("nonce") String nonce,
						   @RequestParam("openid") String openid,
						   @RequestParam("encrypt_type") String encType,
						   @RequestParam("msg_signature") String msgSignature) {
		log.info("=========================开始-接收微信服务器的消息与事件接收URL=========================");
		log.info("=========================消息与事件接收URL接收微信请求：【appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}]," + " timestamp=[{}], nonce=[{}], postData=[\n{}\n]】", appId, openid, signature, encType, msgSignature, timestamp, nonce, postData);
		try {
			//解密消息
			WxOpenConfigStorage wxOpenConfigStorage = new WxOpenInMemoryConfigStorage();
			wxOpenConfigStorage.setComponentAppId(ComponentConfig.sComponentAppId);
			wxOpenConfigStorage.setComponentAesKey(ComponentConfig.sEncodingAESKey);
			wxOpenConfigStorage.setComponentToken(ComponentConfig.sToken);
			wxOpenConfigStorage.setComponentAppSecret(ComponentConfig.sComponentAppSecret);
			WxMpXmlMessage result = WxOpenXmlMessage.fromEncryptedMpXml(postData, wxOpenConfigStorage, timestamp, nonce, msgSignature);
			log.info("====================callback result:"+result.toString());
		} catch (Exception e) {
			e.printStackTrace();
			log.error("=========================解析微信服务器的消息与事件信息异常，【{}】",e.getMessage());
		}
		log.info("=========================结束-接收微信服务器的消息与事件接收URL=========================");
		return "success";
	}

	private void disposeAuthResult(WxOpenXmlMessage result){

	}

	/**
	 * 获取授权二维码页面的地址，并将其返回到前端页面。
	 */
	@GetMapping("/getAuthPage")
	public JsonResult getAuthPage(HttpServletResponse response){
		//Result rs = this.getFailResult();
		log.info("第三方平台生成授权页");
		String authPageURL = "";
		try {
			String preAuthCode = WxThirdUtil.getPreAuthCode();
			log.info("小程序或者公众号授权给第三方平台【预授权码】：" + preAuthCode);

			String componentAppid = ComponentConfig.sComponentAppId;  //第三方平台应用ID
			String redirectUri = ApplicationConfiguration.getServer()+ "/applet/platform/authcode";   //回调URI
			String authType = "2";       //要授权的帐号类型， 1 则商户扫码后，手机端仅展示公众号、2 表示仅展示小程序，3 表示公众号和小程序都展示。
			StringBuilder data = new StringBuilder();
			data.append("?component_appid="+componentAppid);
			data.append("&pre_auth_code="+preAuthCode);
			data.append("&redirect_uri="+redirectUri);
			data.append("&auth_type="+authType);
			authPageURL = WeixinImSetting.OPEN_URL_AUTHPAGE + data;//生成授权页网址
			log.info("第三方平台生成授权页,操作成功");
			return JsonResult.success(authPageURL);
		} catch (Exception e) {
			log.error("第三方平台生成授权页,操作异常", e.getMessage(), e);
			return JsonResult.failWithMsg("第三方平台生成授权页,操作异常:"+e.getMessage());
		}
	}

	/**
	 * 授权回调URL
	 * 接收返回的授权码和过期时间(redirect_url?auth_code=xxx&expires_in=600)
	 * 使用授权码获取授权信息authorization_info（包含接口调用令牌和刷新令牌）
	 */
	@GetMapping("/platform/authcode")
	public String wechatPlatformAauthcode(@RequestParam("auth_code") String authCode){ //, @RequestParam("expires_in") String expiresIn
		log.info("小程序或者公众号授权给第三方平台");
		//清除缓存中的预授权码
		RedisUtil.delete(WebChatCatchUtil.SYS_WEIXIN_OPEN_PRE_AUTH_CODE);
		//redisUtil.del(WebChatCatchUtil.SYS_WEIXIN_OPEN_PREAUTHCODE);
		//Object hasKey_sys_weixin_open_preauthcode_value =  WebChatCatchUtil.getWeixinOpenPreAuthCode();//redisUtil.hasKey(WebChatCatchUtil.SYS_WEIXIN_OPEN_PREAUTHCODE);
		//boolean hasKey_sys_weixin_open_preauthcode = hasKey_sys_weixin_open_preauthcode_value!=null?true:false;
		//log.info("二维码授权完成，清除预授权码成功：" + !hasKey_sys_weixin_open_preauthcode);
		try {
			String accessToken = WxThirdUtil.getOpenAccToken();
			//设置请求参数
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("component_appid", ComponentConfig.sComponentAppId);
			jsonObject.put("authorization_code", authCode);
			String url = WeixinImSetting.OPEN_URL_AUTHORIZERACCESSTOKEN;
			url = url.replace("COMPONENT_ACCESS_TOKEN",accessToken);
			String responseData = HttpUtil.sendPostUrl(url,jsonObject.toString(),"utf-8");
			//String responseData = HttpUtil.sendPostUrl(api_query_auth+ accessToken,jsonObject.toString(),"utf-8");
			JSONObject postData = JSONObject.parseObject(responseData);
			log.info("====================platform/authcode返回post结果：" + postData.toString());

			JSONObject authorizationInfo = (JSONObject) postData.get("authorization_info");   //得到授权信息
			String authorizerAppid = (String) authorizationInfo.get("authorizer_appid");   //得到授权方 APPID    （存入数据库）
			String authorizerAccessToken = (String) authorizationInfo.get("authorizer_access_token");   //得到接口调用令牌
			String authorizerRefreshToken = (String) authorizationInfo.get("authorizer_refresh_token");   //得到接口刷新令牌   存入数据库）
			Integer accessTokenexpiresIn = (Integer) authorizationInfo.get("expires_in");   //接口调用令牌的有效期
			//从数据库中删除数据
			//wxOpenService.delOpenConfigByAppid(authorizerAppid);
			BaseData baseDataDeleteParam = new BaseData();
			baseDataDeleteParam.setCode(authorizerAppid);
			baseDataService.delete(baseDataDeleteParam);
			//新值写入数据库
			//wxOpenService.insertOpenConfig(authorizerAppid,authorizerRefreshToken);
			BaseData baseData = new BaseData();
			baseData.setCode(authorizerAppid);
			baseData.setName("使用授权码获取授权信息");
			baseData.setStatus(CommonConstants.YES);
			baseData.setCreateTime(new Date());
			baseData.setValue(authorizerRefreshToken);
			baseData.setRemark("当用户在第三方平台授权页中完成授权流程后，第三方平台开发者可以在回调 URI 中通过 URL 参数获取授权码。使用以下接口可以换取公众号/小程序的授权信息。建议保存授权信息中的刷新令牌（authorizer_refresh_token）。使用过程中如遇到问题，可在开放平台服务商专区发帖交流。注意： 公众号/小程序可以自定义选择部分权限授权给第三方平台，因此第三方平台开发者需要通过该接口来获取公众号/小程序具体授权了哪些权限，而不是简单地认为自己声明的权限就是公众号/小程序授权的权限。");
			baseData.setUpdateTime(new Date());
			baseDataService.insertSelective(baseData);

			//将授权码写入缓存(HashSet方式(key,item,val,time)->(companyInfo,appid,token,expiresIn))
			WebChatCatchUtil.setWeixinOpenAuthorizerAccessToken(authorizerAppid,authorizerAccessToken,accessTokenexpiresIn);
			WebChatCatchUtil.setWeixinOpenAuthorizerRefreshToken(authorizerAppid,authorizerRefreshToken,60 * 60 * 24 * 7 );//将票刷新缓存写入Redis缓存中 缓存7天
			log.info("=====================platform/authcode小程序或者公众号授权给第三方平台【authorizer_access_token】：" + authorizerAccessToken + "【authorizer_refresh_token】：" + authorizerRefreshToken);
			log.info("=====================platform/authcode小程序或者公众号授权给第三方平台,操作成功");
		} catch (Exception e) {
			log.error("小程序或者公众号授权给第三方平台,操作异常", e.getMessage(), e);
		}
		return "success";  //扫码成功后跳转到 success.html页面 或者给予提示信息
	}


	/**
	 * 上传小程序代码并生成体验版
	 * @author ligguanjun
	 * @date 2022-01-17 17:18
	 */
	@GetMapping("/getTemplateList")
	public JsonResult<String> getTemplateList(){
		String accessToken = WxThirdUtil.getOpenAccToken();
		String url = WeixinImSetting.WXA_GET_TEMPLATE_LIST;
		url = url.replace("ACCESS_TOKEN",accessToken);
		String responseData = HttpUtil.sendGet(url,"utf-8");
		//String responseData = HttpUtil.sendPostUrl(api_query_auth+ accessToken,jsonObject.toString(),"utf-8");
		JSONObject postData = JSONObject.parseObject(responseData);
		log.info("====================getTemplateList返回post结果：" + postData.toString());
		if("0".equals(postData.getString("errcode")) && "ok".equalsIgnoreCase(postData.getString("errmsg"))){
			return JsonResult.success();
		} else {
			return JsonResult.failWithMsg(postData.getInteger("errcode")+postData.getString("errmsg"));
		}
	}


	/**
	 * 上传小程序代码并生成体验版
	 * @author ligguanjun
	 * @date 2022-01-17 17:18
	 */
	@PostMapping("/commitApplet")
	public JsonResult<String> commitApplet(@RequestBody JSONObject param){
		String authorizerAppid = param.getString("authorizerAppid");
		if(EmptyUtils.isEmpty(authorizerAppid)){
			return JsonResult.failWithMsg("授权方appid[authorizerAppid]不能传空");
		}
		String authorizerRefreshToken = WebChatCatchUtil.getWeixinOpenAuthorizerRefreshToken(authorizerAppid);
		if(EmptyUtils.isEmpty(authorizerRefreshToken)){
			return JsonResult.failWithMsg("获取刷新缓存authorizerRefreshToken失败");
		}
		String authorizerAccessToken = WxThirdUtil.getAuthorizerAccessToken(authorizerAppid, authorizerRefreshToken);
		if(EmptyUtils.isEmpty(authorizerAccessToken)){
			return JsonResult.failWithMsg("获取authorizerAccessToken失败");
		}
		//设置请求参数
		String template_id = param.getString("template_id");
		String user_version = param.getString("user_version");
		String user_desc = param.getString("user_desc");
		String ext_json = param.getString("ext_json");
		if(EmptyUtils.isEmpty(template_id)){
			return JsonResult.failWithMsg("代码库中的代码模板 ID[template_id]不能传空");
		}
		if(EmptyUtils.isEmpty(user_version)){
			return JsonResult.failWithMsg("代码版本号[user_version]不能传空");
		}
		if(EmptyUtils.isEmpty(ext_json)){

		}
		if(EmptyUtils.isEmpty(user_desc)){
			user_desc = "test";
		}
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("template_id", template_id);
		jsonObject.put("user_version", user_version);
		jsonObject.put("user_desc", user_desc);
		jsonObject.put("ext_json", ext_json);
		/*jsonObject.put("template_id", "0");
		jsonObject.put("user_version", "V1.0.0");
		jsonObject.put("user_desc", "test");
		JSONObject obj = new JSONObject();
		obj.put("extAppid", "");
		Map<String, Object> map = new HashMap<>();
		map.put("merchantId", "");
		map.put("userVersion", "");
		obj.put("ext", map);
		map = new HashMap<>();
		Map<String, Object> maps = new HashMap<>();
		maps.put("pages/index/index", map);
		obj.put("extPages", maps);
		jsonObject.put("ext_json", JSONObject.toJSONString(obj));*/
		String url = WeixinImSetting.WXA_COMMIT;
		url = url.replace("ACCESS_TOKEN",authorizerAccessToken);
		String responseData = HttpUtil.sendPostUrl(url,jsonObject.toString(),"utf-8");
		//String responseData = HttpUtil.sendPostUrl(api_query_auth+ accessToken,jsonObject.toString(),"utf-8");
		JSONObject postData = JSONObject.parseObject(responseData);
		log.info("====================commitApplet返回post结果：" + postData.toString());
		if("0".equals(postData.getString("errcode")) && "ok".equalsIgnoreCase(postData.getString("errmsg"))){
			return JsonResult.success();
		} else {
			return JsonResult.failWithMsg("====================commitApplet返回post结果：" +postData.getInteger("errcode")+postData.getString("errmsg"));
		}
	}



	/**
	 * 手动更新小程序服务商平台相关redis缓存
	 * @author liuguanjun
	 * @date 2022-01-17 14:33:52
	 **/
	@PostMapping(value = "refreshRedis")
	public JsonResult<Object> cancelOrderById(@RequestBody JSONObject param) {
		String redisName = param.getString("redisName");
		String redisValue = param.getString("redisValue");
		Integer redisTime = param.getInteger("redisTime");
		log.info("redisName: " + redisName+",redisValue: " + redisValue+",redisTime: " + redisTime);
		RedisUtil.delete(redisName);
		RedisUtil.set(redisName,redisValue,redisTime);
		log.info("redisName: " + redisName+",redisValue: " + RedisUtil.get(redisName));
		return JsonResult.success();
	}
	

}
